package com.yxx.strategy.loginStrategyImpl;

import com.yxx.config.properties.QqProperties;
import com.yxx.constant.LoginConstant;
import com.yxx.entityModel.dto.*;
import com.yxx.entityModel.dto.SocialUserInfoDTO;
import com.yxx.entityModel.vo.request.CodeRequest;
import com.yxx.enums.LoginTypeEnum;
import com.yxx.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import java.net.URI;
import java.util.Objects;

/**
 * QQ 登录策略
 * @author yuxiangxun
 * @date 2025/2/6
 * @apiNote
 */
@Service
@Slf4j
public class QqLoginStrategyImpl extends AbstractLoginStrategyImpl{

    @Resource
    private QqProperties qqProperties;

    @Resource
    private RestTemplate restTemplate;

    /**
     * 获取 QQ 第三方Token
     * 模板方法
     * @param data data
     * @return 第三方Token
     */
    @Override
    public SocialTokenDTO getSocialTokenDTO(CodeRequest data) {
        // 获取 QQ 上的 Token
        TokenDTO qqToken = getQqToken(data.getCode());
        // 通过 QQToken中的access_token 获取用户信息，以便于获取到用户的 openId
        QqTokenDTO userOpenId = getUserOpenId(qqToken.getAccess_token());
        // 封装 QQ 第三方Token 并返回
        return SocialTokenDTO.builder()
                .openId(userOpenId.getOpenid())
                .accessToken(qqToken.getAccess_token())
                .loginType(LoginTypeEnum.QQ.getLoginType())
                .build();
    }

    /**
     * 获取 QQ 上的 Token
     * @param code
     * @return
     */
    private TokenDTO getQqToken(String code){
        try{
            // 根据 code 换取 accessToken
            MultiValueMap<String,String> queryMap = new LinkedMultiValueMap<>(6);
            // 封装 QQ 的请求参数
            queryMap.set(LoginConstant.GRANT_TYPE, qqProperties.getGrantType());
            queryMap.set(LoginConstant.CODE, code);
            queryMap.set(LoginConstant.CLIENT_ID, qqProperties.getAppId());
            queryMap.set(LoginConstant.CLIENT_SECRET, qqProperties.getAppKey());
            queryMap.set(LoginConstant.REDIRECT_URI, qqProperties.getRedirectUrl());
            queryMap.set(LoginConstant.FMT,"json");
            UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(qqProperties.getAccessTokenUrl());
            URI uri = uriComponentsBuilder.queryParams(queryMap).build().toUri();
            return restTemplate.getForObject(uri,TokenDTO.class);
        } catch (Exception e){
            log.error("getQqToken is error, {}", e.getMessage());
            throw new ServiceException("QQ登录错误");
        }
    }

    /**
     * 获取 QQ 用户的 openId
     * @param AccessToken
     * @return
     */
    private QqTokenDTO getUserOpenId(String AccessToken){
        try{
            // 返回用户 OpenId
            MultiValueMap<String,String> queryMap = new LinkedMultiValueMap<>(2);
            // 请求参数
            queryMap.set(LoginConstant.ACCESS_TOKEN,AccessToken);
            queryMap.set(LoginConstant.FMT,"json");
            UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(qqProperties.getUserOpenIdUrl());
            URI uri = uriComponentsBuilder.queryParams(queryMap).build().toUri();
            return restTemplate.getForObject(uri,QqTokenDTO.class);
        }catch (RestClientException e){
            log.info("getUserOpenId is error,{}",e.getMessage());
            throw new ServiceException("QQ登录错误");
        }
    }


    /**
     * 获取 QQ 第三方用户信息
     * @param socialTokenDTO 第三方token
     * @return
     */
    @Override
    public SocialUserInfoDTO getSocialUserInfo(SocialTokenDTO socialTokenDTO) {
        // 定义请求参数
        MultiValueMap<String,String> queryMap = new LinkedMultiValueMap<>(3);
        queryMap.set(LoginConstant.QQ_OPEN_ID,socialTokenDTO.getOpenId());
        queryMap.set(LoginConstant.OAUTH_CONSUMER_KEY,qqProperties.getAppId());
        queryMap.set(LoginConstant.ACCESS_TOKEN,socialTokenDTO.getAccessToken());
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(qqProperties.getUserInfoUrl());
        URI uri = uriComponentsBuilder.queryParams(queryMap).build().toUri();
        // 获取QQ返回的用户信息
        QqUserInfoDTO qqUserInfo = restTemplate.getForObject(uri, QqUserInfoDTO.class);
        // 返回用户信息
        return SocialUserInfoDTO.builder()
                .id(socialTokenDTO.getOpenId())
                .nickname(Objects.requireNonNull(qqUserInfo).getNickname())
                .avatar(qqUserInfo.getFigureurl_qq_1())
                .build();
    }
}
